﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Toolkit.Web.Infastructure;

namespace Toolkit.Web.ViewComponents.DataGrid
{
    public sealed class DataGridPagination
    {
        private int _currentPageIndex;

        public DataGridPagination()
        {
            HtmlAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            HtmlBuilder = new DataGridPaginationHtmlBuilder(this);

            if (PageSizeOptions == null)
            {
                PageSizeOptions = new List<int>();
            }
        }

        public DataGridPagination(int recordStartIndex, int recordSetSize, int? totalRecordCount)
            : this()
        {
            if (recordStartIndex < 0)
            {
                throw new ArgumentOutOfRangeException("recordStartIndex");
            }

            if (recordSetSize <= 0)
            {
                throw new ArgumentOutOfRangeException("recordSetSize");
            }

            if (totalRecordCount.HasValue && totalRecordCount.Value < 0)
            {
                throw new ArgumentOutOfRangeException("totalRecordCount");
            }

            NumberOfResults = totalRecordCount;
            PageSize = recordSetSize;
            PageIndex = (int)Math.Floor(((double)recordStartIndex) / ((double)recordSetSize));
        }

        public DataGridPaginationHtmlBuilder HtmlBuilder
        {
            get;
            set;
        }

        public IDictionary<string, object> HtmlAttributes
        {
            get;
            private set;
        }

        public int PageIndex
        {
            get
            {
                if (_currentPageIndex < 0)
                {
                    _currentPageIndex = 0;
                }
                return _currentPageIndex;
            }
            set
            {
                if (value <= 0)
                {
                    _currentPageIndex = 0;
                }
                else
                {
                    _currentPageIndex = value;
                }
            }
        }

        public int PageSize
        {
            get;
            set;
        }

        public int? NumberOfResults
        {
            get;
            set;
        }

        public int? NumberOfPages
        {
            get
            {
                if (!NumberOfResults.HasValue)
                {
                    return null;
                }

                return (int)Math.Ceiling(((double)NumberOfResults.Value) / ((double)PageSize));
            }
        }

        public int VisiblePageOffset
        {
            get;
            set;
        }

        public int FirstPageIndex
        {
            get
            {
                return 0;
            }
        }

        public int? LastPageIndex
        {
            get
            {
                if (!NumberOfPages.HasValue)
                {
                    return null;
                }

                return NumberOfPages.Value - 1;
            }
        }

        public IList<int> PageSizeOptions
        {
            get;
            set;
        }

        public bool EnablePageSizeSelection
        {
            get;
            set;
        }

        public bool EnablePageIndexSelection
        {
            get;
            set;
        }

        public bool IsFirstPage
        {
            get
            {
                return (PageIndex == FirstPageIndex);
            }
        }

        public bool IsLastPage
        {
            get
            {
                return (
                    LastPageIndex.HasValue &&
                    PageIndex == LastPageIndex.Value
                );
            }
        }

        public int PreviousPageIndex
        {
            get
            {
                return Math.Max(FirstPageIndex, PageIndex - 1);
            }
        }

        public int NextPageIndex
        {
            get
            {
                if (!LastPageIndex.HasValue)
                {
                    return PageIndex + 1;
                }

                return Math.Min(LastPageIndex.Value, PageIndex + 1);
            }
        }

        public IList<int> GetPriorVisibleOffsetPageOptions()
        {
            List<int> priorVisiblePages = new List<int>();

            for (int i = (PageIndex - 1); (i >= (PageIndex - VisiblePageOffset) && i >= FirstPageIndex); i--)
            {
                if (i > FirstPageIndex)
                {
                    priorVisiblePages.Add(i);
                }
            }

            priorVisiblePages.Sort();

            return priorVisiblePages;
        }

        public IList<int> GetPostVisibleOffsetPageOptions()
        {
            List<int> postVisiblePages = new List<int>();

            if (LastPageIndex.HasValue)
            {
                for (int i = (PageIndex + 1); (i <= (PageIndex + VisiblePageOffset) && i <= LastPageIndex.Value); i++)
                {
                    if (i < LastPageIndex.Value)
                    {
                        postVisiblePages.Add(i);
                    }
                }

                postVisiblePages.Sort();
            }

            return postVisiblePages;
        }

        public bool DoPriorHiddenPageOptionsExist()
        {
            return (((PageIndex + 1) - GetPriorVisibleOffsetPageOptions().Count) > 2);
        }

        public bool DoPostHiddenPageOptionsExist()
        {
            if (!NumberOfPages.HasValue)
            {
                return true;
            }
            if (VisiblePageOffset == 0)
            {
                return (PageIndex < (NumberOfPages - 1));
            }
            return (NumberOfPages.Value >= ((PageIndex + 1) + (VisiblePageOffset * 2) - 1));
        }

        public bool IsCurrentPage(int page)
        {
            return (page == PageIndex);
        }
    }
}
